package com.sc.nft.service.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.sc.nft.entity.*;
import com.sc.nft.entity.vo.MallDeliveryAddressVO;
import com.sc.nft.entity.vo.OrderPreviewProductCheckVO;
import com.sc.nft.entity.vo.mall.*;
import com.sc.nft.entity.vo.mall.req.WxMiniOrderCreateByCartReq;
import com.sc.nft.entity.vo.mall.req.WxMiniOrderCreateReq;
import com.sc.nft.entity.vo.mall.req.WxMiniOrderPreviewByCartReq;
import com.sc.nft.entity.vo.mall.req.WxMiniOrderPreviewReq;
import com.sc.nft.enums.*;
import com.sc.nft.enums.mallcart.CartStatusEnum;
import com.sc.nft.enums.task.ParticipantsEnum;
import com.sc.nft.exception.GlobalRunTimeException;
import com.sc.nft.feign.WxMallCartClient;
import com.sc.nft.helper.SmartSupplyHelper;
import com.sc.nft.pool.UserPool;
import com.sc.nft.req.mallCart.CartListReq;
import com.sc.nft.req.mallCart.CartSettleReq;
import com.sc.nft.req.mallCart.CartSettleReqs;
import com.sc.nft.service.*;
import com.sc.nft.sup.ErrorCode;
import com.sc.nft.sup.Result;
import com.sc.nft.util.BigDecimalUtils;
import com.sc.nft.util.OrderNoUtil;
import com.sc.nft.vo.mallcart.MallCartListVO;
import jodd.typeconverter.Convert;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 小程序订单实现
 *
 * @Author：LiGen
 * @Package：com.sc.nft.service.impl
 * @Project：sc_metago
 * @name：WxMiniMallOrderServiceImpl
 * @Date：2024/5/16 15:02
 * @Filename：WxMiniMallOrderServiceImpl
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class WxMiniMallOrderServiceImpl implements WxMiniMallOrderService {

    private final MallActivityService mallActivityService;
    private final MallActivitySpecsService mallActivitySpecsService;
    private final UserCollectionService userCollectionService;
    private final MallOrderProductService mallOrderProductService;
    private final MallDeliveryAddressService mallDeliveryAddressService;
    private final MallProductService mallProductService;
    private final MallProductSpecsService mallProductSpecsService;
    private final WxMallCartClient wxMallCartClient;
    private final UserCreatorInfoService userCreatorInfoService;
    private final SmartSupplyHelper smartSupplyHelper;

    /**
     * 小程序订单预览
     *
     * @param wxMiniOrderPreviewReq
     * @param wxMiniUserInfo
     * @return
     */
    @Override
    public MiniMallOrderPreviewVO miniMallOrderPreview(WxMiniOrderPreviewReq wxMiniOrderPreviewReq, WxMiniUserInfo wxMiniUserInfo) {
        MiniMallOrderPreviewVO miniMallOrderPreviewVO = new MiniMallOrderPreviewVO();
        // 商品校验并获取活动商品信息
        OrderPreviewProductVO orderPreviewProductVO = miniMallOrderPreviewCheck(wxMiniOrderPreviewReq.getActivityId(), wxMiniOrderPreviewReq.getActivitySpecsId(), wxMiniOrderPreviewReq.getBuyCount(), wxMiniUserInfo).getOrderPreviewProductVO();
        // 获取地址信息
        MallDeliveryAddressVO defaultAddress = mallDeliveryAddressService.getDefaultAddress(wxMiniUserInfo.getUserId());
        if (Objects.nonNull(defaultAddress)){
            OrderPreviewAddressVO orderPreviewAddressVO = new OrderPreviewAddressVO();
            BeanUtils.copyProperties(defaultAddress, orderPreviewAddressVO);
            miniMallOrderPreviewVO.setPreviewAddress(orderPreviewAddressVO);
        }
        miniMallOrderPreviewVO.setProducts(Lists.newArrayList(orderPreviewProductVO));
        miniMallOrderPreviewVO.setTotalPrice(orderPreviewProductVO.getSum());
        miniMallOrderPreviewVO.setActualPayPrice(orderPreviewProductVO.getSum());
        return miniMallOrderPreviewVO;
    }

    /**
     * 小程序订单预览(通过购物车)
     *
     * @param wxMiniOrderPreviewByCartReq
     * @param wxMiniUserInfo
     * @return
     */
    @Override
    public MiniMallOrderPreviewVO miniMallOrderPreviewByCart(WxMiniOrderPreviewByCartReq wxMiniOrderPreviewByCartReq, WxMiniUserInfo wxMiniUserInfo) {
        MiniMallOrderPreviewVO miniMallOrderPreviewVO = new MiniMallOrderPreviewVO();
        // 获取需要创建订单的购物车列表
        Result<List<MallCartListVO>> listResult = wxMallCartClient.cartList(CartListReq.build(wxMiniOrderPreviewByCartReq.getCartIds(), wxMiniUserInfo.getId()));
        List<MallCartListVO> mallCartListVOList = listResult.getData();
        List<OrderPreviewProductVO> orderPreviewProductVOList = new ArrayList<>();
        for (MallCartListVO mallCartListVO : mallCartListVOList) {
            Assert.isTrue(CartStatusEnum.NORMAL == mallCartListVO.getStatus(), () -> new GlobalRunTimeException("已创建订单,请勿重复创建"));
            // 商品校验并获取活动商品信息
            OrderPreviewProductVO orderPreviewProductVO = miniMallOrderPreviewCheck(mallCartListVO.getActivityId(), mallCartListVO.getActivitySpecsId(), mallCartListVO.getActivitySpecsNum(), wxMiniUserInfo).getOrderPreviewProductVO();

            orderPreviewProductVOList.add(orderPreviewProductVO);
        }
        // 获取地址信息
        MallDeliveryAddressVO defaultAddress = mallDeliveryAddressService.getDefaultAddress(wxMiniUserInfo.getUserId());
        if(Objects.nonNull(defaultAddress)){
            OrderPreviewAddressVO orderPreviewAddressVO = new OrderPreviewAddressVO();
            BeanUtils.copyProperties(defaultAddress, orderPreviewAddressVO);
            miniMallOrderPreviewVO.setPreviewAddress(orderPreviewAddressVO);
        }
        miniMallOrderPreviewVO.setProducts(orderPreviewProductVOList);
        BigDecimal totalPrice = orderPreviewProductVOList.stream().map(OrderPreviewProductVO::getSum).reduce(BigDecimal::add).orElse(BigDecimal.ZERO);
        miniMallOrderPreviewVO.setTotalPrice(totalPrice);
        miniMallOrderPreviewVO.setActualPayPrice(totalPrice);
        return miniMallOrderPreviewVO;
    }

    /**
     * 小程序下单预览校验
     *
     * @param activityId
     * @param activitySpecsId
     * @param buyCount
     * @param wxMiniUserInfo
     */
    private OrderPreviewProductCheckVO miniMallOrderPreviewCheck(Long activityId, Long activitySpecsId, Integer buyCount, WxMiniUserInfo wxMiniUserInfo) {
        DateTime now = DateTime.now();
        //获取活动商品信息
        MallActivity mallActivity = mallActivityService.getCanBuy(activityId);
        //商品已下架
        Assert.notNull(mallActivity, () -> new GlobalRunTimeException(ErrorCode.MALL_THE_PRODUCT_IS_NO_LONGER_AVAILABLE));
        // 活动商品未开始
        Assert.isFalse(now.before(mallActivity.getStartTime()), () -> new GlobalRunTimeException(ErrorCode.NOT_BEGIN));

        Assert.isTrue(now.isAfter(mallActivity.getStartTime()), () -> new GlobalRunTimeException(ErrorCode.MALL_THE_PRODUCT_IS_NO_LONGER_AVAILABLE));
        // 获取活动商品规格信息
        MallActivitySpecs mallActivitySpecs = mallActivitySpecsService.getById(activitySpecsId);
        //营销活动规格是否存在
        Assert.notNull(mallActivitySpecs, () -> new GlobalRunTimeException(ErrorCode.MALL_PRODUCT_SPECIFICATION_DOES_NOT_EXIST));
        //校验参与对象
        if (mallActivity.getParticipants() == ParticipantsEnum.APPOINT) {
            //如果是指定NFT
            Long collectionId = mallActivity.getCollectionId();
            //判断id是否为空
            Assert.notNull(collectionId, () -> new GlobalRunTimeException(ErrorCode.COLLECTION_NOT_FOUND));
            //判断id是否为0
            Assert.isFalse(collectionId == 0L, () -> new GlobalRunTimeException(ErrorCode.MALL_THE_PRODUCT_IS_NO_LONGER_AVAILABLE));
            //不满足兑换条件
            Assert.isTrue(userCollectionService.getIsContainsAndIsHoldAndIsOpenAndOnConsignByCollectionId(collectionId, wxMiniUserInfo.getUserId()) > 0, () -> new GlobalRunTimeException(ErrorCode.DOES_NOT_MEET_THE_REDEMPTION_CONDITIONS));
        }
        //数量不足
        Assert.isTrue(mallActivitySpecs.getUsableStockCount() - buyCount >= 0, () -> new GlobalRunTimeException(ErrorCode.INSUFFICIENT_STOCK));

        //校验购买上限(小程序订单)
        Integer userBuyCount = mallOrderProductService.getMiniUserBuyCountByUserIdAndActivityId(wxMiniUserInfo.getId(), mallActivity.getId());
        Assert.isTrue(userBuyCount + buyCount <= mallActivity.getBuyLimit(), () -> new GlobalRunTimeException(ErrorCode.MALL_THE_CURRENT_PURCHASE_QUANTITY_HAS_REACHED_THE_UPPER_LIMIT));
        MallProduct mallProduct = mallProductService.getById(mallActivity.getProductId());
        MallProductSpecs mallProductSpecs = mallProductSpecsService.getById(mallActivitySpecs.getSpecsId());
        OrderPreviewProductVO orderPreviewProductVO = new OrderPreviewProductVO();
        orderPreviewProductVO.setProductName(mallProduct.getProductName());
        orderPreviewProductVO.setProductImg(mallProduct.getThumbnail());
        orderPreviewProductVO.setSpecsName(mallProductSpecs.getSpecsName());
        orderPreviewProductVO.setPrice(mallActivitySpecs.getSalesPrice());
        orderPreviewProductVO.setCount(buyCount);
        BigDecimal totalPrice = mallActivitySpecs.getSalesPrice().multiply(Convert.toBigDecimal(buyCount)).setScale(2, BigDecimal.ROUND_DOWN);
        orderPreviewProductVO.setSum(totalPrice);
        OrderPreviewProductCheckVO orderPreviewProductCheckVO = new OrderPreviewProductCheckVO();
        orderPreviewProductCheckVO.setOrderPreviewProductVO(orderPreviewProductVO);
        orderPreviewProductCheckVO.setMallActivity(mallActivity);
        orderPreviewProductCheckVO.setMallActivitySpecs(mallActivitySpecs);
        orderPreviewProductCheckVO.setMallProduct(mallProduct);
        orderPreviewProductCheckVO.setMallProductSpecs(mallProductSpecs);
        return orderPreviewProductCheckVO;
    }

    /**
     * 小程序订单创建
     *
     * @param wxMiniOrderCreateReq
     * @param wxMiniUserInfo
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public MiniMallOrderConfirmVO miniMallOrderCreate(WxMiniOrderCreateReq wxMiniOrderCreateReq, WxMiniUserInfo wxMiniUserInfo) {
        DateTime now = DateTime.now();
        OrderPreviewProductCheckVO orderPreviewProductCheckVO = miniMallOrderPreviewCheck(wxMiniOrderCreateReq.getActivityId(), wxMiniOrderCreateReq.getActivitySpecsId(), wxMiniOrderCreateReq.getBuyCount(), wxMiniUserInfo);
        MallOrder mallOrder = create(orderPreviewProductCheckVO, wxMiniUserInfo, wxMiniOrderCreateReq.getMallDeliveryAddressId(), wxMiniOrderCreateReq.getRecommendedUserId(), now).getMallOrder();
        return MiniMallOrderConfirmVO.build(Lists.newArrayList(mallOrder.getId()));
    }

    /**
     * 小程序订单创建
     *
     * @param wxMiniOrderCreateByCartReq
     * @param wxMiniUserInfo
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public MiniMallOrderConfirmVO miniMallOrderCreateByCart(WxMiniOrderCreateByCartReq wxMiniOrderCreateByCartReq, WxMiniUserInfo wxMiniUserInfo, List<MallCartListVO> mallCartListVOList) {
        DateTime now = DateTime.now();
        // 购物车对应的商品信息
        Map<Long, OrderPreviewProductCheckVO> orderPreviewProductCheckVOMap = new HashMap<>();
        for (MallCartListVO mallCartListVO : mallCartListVOList) {
            Assert.isTrue(CartStatusEnum.NORMAL == mallCartListVO.getStatus(), () -> new GlobalRunTimeException("已创建订单,请勿重复创建"));
            OrderPreviewProductCheckVO orderPreviewProductCheckVO = miniMallOrderPreviewCheck(mallCartListVO.getActivityId(), mallCartListVO.getActivitySpecsId(), mallCartListVO.getActivitySpecsNum(), wxMiniUserInfo);
            orderPreviewProductCheckVOMap.put(mallCartListVO.getId(), orderPreviewProductCheckVO);
        }
        List<MallOrder> mallOrderList = new ArrayList<>();
        // 购物车结算请求参数
        List<CartSettleReq> cartSettleReqList = new ArrayList<>();
        for (Long cartId : orderPreviewProductCheckVOMap.keySet()) {
            OrderPreviewProductCheckVO orderPreviewProductCheckVO = orderPreviewProductCheckVOMap.get(cartId);
            MiniCreateOrderReturn miniCreateOrderReturn = create(orderPreviewProductCheckVO, wxMiniUserInfo, wxMiniOrderCreateByCartReq.getMallDeliveryAddressId(), null, now);
            mallOrderList.add(miniCreateOrderReturn.getMallOrder());
            CartSettleReq cartSettleReq = new CartSettleReq();
            cartSettleReq.setCartId(cartId);
            cartSettleReq.setMiniUserId(wxMiniUserInfo.getId());
            cartSettleReq.setOrderId(miniCreateOrderReturn.getMallOrder().getId());
            cartSettleReq.setOrderProductId(miniCreateOrderReturn.getMallOrderProduct().getId());
            cartSettleReqList.add(cartSettleReq);
        }
        // 购物车结算
        wxMallCartClient.settleCart(CartSettleReqs.build(cartSettleReqList));
        return MiniMallOrderConfirmVO.build(mallOrderList.stream().map(mallOrder -> mallOrder.getId()).collect(Collectors.toList()));
    }

    /**
     * 创建
     *
     * @param orderPreviewProductCheckVO
     * @param wxMiniUserInfo
     * @param mallDeliveryAddressId
     * @return
     */
    public MiniCreateOrderReturn create(OrderPreviewProductCheckVO orderPreviewProductCheckVO, WxMiniUserInfo wxMiniUserInfo, Long mallDeliveryAddressId, Long recommendedUserId, Date now) {
        OrderPreviewProductVO orderPreviewProductVO = orderPreviewProductCheckVO.getOrderPreviewProductVO();
        MallActivity mallActivity = orderPreviewProductCheckVO.getMallActivity();
        MallActivitySpecs mallActivitySpecs = orderPreviewProductCheckVO.getMallActivitySpecs();
        MallProduct mallProduct = orderPreviewProductCheckVO.getMallProduct();
        MallProductSpecs mallProductSpecs = orderPreviewProductCheckVO.getMallProductSpecs();
        // 获取地址信息
        MallDeliveryAddress mallDeliveryAddress = mallDeliveryAddressService.getAddressByUserIdAndId(wxMiniUserInfo.getUserId(), mallDeliveryAddressId);
        // 创建订单
        MallOrder mallOrder = new MallOrder();
        mallOrder.setUserId(wxMiniUserInfo.getUserId());
        mallOrder.setMiniUserId(wxMiniUserInfo.getId());
        mallOrder.setRecommendedUserId(recommendedUserId);
        // 小程序订单
        mallOrder.setOrderSource(SourceEnum.MINI_MALL_APP);
        mallOrder.setOrderNo(OrderNoUtil.getOrderNo());
        mallOrder.setStatus(MallOrderStatusEnum.WAIT_PAY);
        mallOrder.setRefundStatus(MallOrderRefundStatusEnum.NEW_NOT_APPLY);
        mallOrder.setIsVirtual(Boolean.FALSE);
        // 塞入地址
        mallOrder.setUserRealName(mallDeliveryAddress.getRecipientName());
        mallOrder.setUserTel(mallDeliveryAddress.getContactNumber());
        mallOrder.setProvince(mallDeliveryAddress.getState());
        mallOrder.setCity(mallDeliveryAddress.getCity());
        mallOrder.setArea(mallDeliveryAddress.getArea());
        mallOrder.setUserAddress(mallDeliveryAddress.getDetailedAddress());
        //成本价
        BigDecimal costPrice = mallActivitySpecs.getCostPrice();
        // 活动成本
        BigDecimal activityCostPrice = mallActivitySpecs.getActivityCostPrice();
        // 拖低价
        BigDecimal reservePrice = mallActivitySpecs.getReservePrice();
        //商品总价
        mallOrder.setTotalPrice(orderPreviewProductVO.getSum());
        //实际需要支付的价格
        mallOrder.setRealPrice(orderPreviewProductVO.getSum());
        mallOrder.setTotalNum(orderPreviewProductVO.getCount());
        mallOrder.setPayPostage(BigDecimal.ZERO);
        mallOrder.setPayPrice(orderPreviewProductVO.getSum());
        //类型  品牌销售 活动兑换
        mallOrder.setActivityType(mallActivity.getActivityType());
        mallOrder.setDaoId(mallProduct.getDaoId());
        mallOrder.setDaoName(userCreatorInfoService.getById(mallProduct.getDaoId()).getDaoName());
        //订单有效期
        mallOrder.setExpiredTime(DateUtil.offsetMinute(now, 30));
        if (mallProduct.getProductChannel() == MallChannelEnum.SMART) {
            JSONObject result = smartSupplyHelper.createOrder(mallProduct, mallProductSpecs, mallOrder);
            try {
                JSONObject data = result.getJSONObject("data");
                JSONObject resultObject = data.getJSONArray("orderDetailList").getJSONObject(0);
                mallOrder.setSupplyOrderNo(data.getString("result"));
                mallOrder.setApiOrderNo(resultObject.getString("apiOrderSn"));
                mallOrder.setSupplyOrderId(resultObject.getLong("id"));
            } catch (Exception e) {
                log.error("智慧供应链返回结构解析失败,result:{}", result, e);
            }
        }
        mallOrder.insert();
        //订单关联商品表
        MallOrderProduct mallOrderProduct = new MallOrderProduct();
        mallOrderProduct.setActivityType(mallActivity.getActivityType());
        mallOrderProduct.setMallOrderId(mallOrder.getId());
        mallOrderProduct.setProductId(mallActivity.getProductId());
        mallOrderProduct.setActivityId(mallActivity.getId());
        mallOrderProduct.setActivitySpecsId(mallActivitySpecs.getId());
        mallOrderProduct.setProductSalesPrice(orderPreviewProductVO.getPrice());
        mallOrderProduct.setProductCostPrice(costPrice);
        mallOrderProduct.setActivityCostPrice(activityCostPrice);
        mallOrderProduct.setReservePrice(reservePrice);
        mallOrderProduct.setProductNum(orderPreviewProductVO.getCount());
        mallOrderProduct.setThumbnail(mallProduct.getThumbnail());
        mallOrderProduct.setProductName(mallProduct.getProductName());
        mallOrderProduct.setProductSpecsName(mallProductSpecs.getSpecsName());
        mallOrderProduct.insert();

        //扣减库存
        Assert.isTrue(mallActivitySpecsService.frozenStockByIdAndCount(mallActivitySpecs.getId(), orderPreviewProductVO.getCount()), () -> new GlobalRunTimeException(ErrorCode.THE_SYSTEM_IS_BUSY_PLEASE_TRY_AGAIN_LATER));
        // 订单日志
        MallOrderStatusLog mallOrderStatusLog = new MallOrderStatusLog();
        mallOrderStatusLog.setMallOrderId(mallOrder.getId());
        mallOrderStatusLog.setChangeType(MallOrderStatusEnum.WAIT_PAY.name());
        mallOrderStatusLog.setChangeMessage(MallOrderStatusEnum.WAIT_PAY.getDescription());
        mallOrderStatusLog.setIsRefund(Boolean.FALSE);
        mallOrderStatusLog.setRemark("下单时间");
        mallOrderStatusLog.insert();
        MiniCreateOrderReturn miniCreateOrderReturn = new MiniCreateOrderReturn();
        miniCreateOrderReturn.setMallOrder(mallOrder);
        miniCreateOrderReturn.setMallOrderProduct(mallOrderProduct);
        return miniCreateOrderReturn;
    }
}
